package com.ibm.cloud.banking.customer.service;

import com.ibm.cloud.banking.constant.TransErrorMgt;
import com.ibm.cloud.banking.customer.components.CustomerBasisComponent;
import com.ibm.cloud.banking.customer.components.CustomerCertificateBasisComponent;
import com.ibm.cloud.banking.customer.entity.CustomerAccountRel;
import com.ibm.cloud.banking.customer.entity.CustomerCertificate;
import com.ibm.cloud.banking.customer.entity.CustomerInfo;
import com.ibm.cloud.banking.facade.customer.ICustomerCommandFacade;
import com.ibm.cloud.banking.facade.customer.ICustomerQueryFacade;
import com.ibm.cloud.banking.facade.customer.dto.CreateCustomerDTO;
import com.ibm.cloud.banking.facade.customer.dto.CustAcctRelDTO;
import com.ibm.cloud.banking.facade.customer.dto.CustomerAccountRelDTO;
import com.ibm.cloud.banking.facade.customer.dto.CustomerCertificateDTO;
import com.ibm.cloud.banking.facade.customer.dto.QueryCustomerRespDTO;
import com.ibm.cloud.banking.platform.exception.BusinessException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import io.netty.util.internal.StringUtil;

@Service
public class CustomerDomainService implements ICustomerQueryFacade, ICustomerCommandFacade {
	
	static final Logger logger = LoggerFactory.getLogger(CustomerDomainService.class);

	@Autowired
	private CustomerCertificateBasisComponent certificateDataComponent;

//	@Autowired
//	IAccountFacade accountFacade;


//	@Autowired
//	CustomerOperationLogBasisCpnt customerOperationLogBasisCpnt;

//	@Autowired
//	private SnowFlakeIdGenerator snowFlakeIdGenerator;

	@Autowired
	CustomerBasisComponent customerDataComponent;

	private static int OPERATE_TYPE_MODIFY = 1;
	private static int OPERATE_TYPE_CREATE = 0;

	@Override
	public String generateCustNo(CreateCustomerDTO customer){
		return customerDataComponent.generateCustNo(customer.getType());
	}

	public String generateCustNo(String type){
		return customerDataComponent.generateCustNo(type);
	}

	@Override
	public boolean isExist(CustomerCertificateDTO customer){

		checkCustInputValues(customer);

		CustomerCertificate customerCertificate = certificateDataComponent.
				getCustomerCertificate(customer.getIdType(),
						customer.getIdNo(),customer.getName());

		// 如果为建设客户，且已经存在，抛出异常
		if(customer.getOperate()==OPERATE_TYPE_CREATE && customerCertificate!=null){
			// 提前校验参数，避免保存客户证件信息成功，而保存客户信息时失败
			//checkCustExtendInputValues(customer);
			throw new BusinessException(TransErrorMgt.CUSTOMER_CERTIFICATE_IS_EXIST.code,
					String.format(TransErrorMgt.CUSTOMER_CERTIFICATE_IS_EXIST.message,customerCertificate.getCustomerNo()));
		}

		// 如果为更新操作，且客户证件信息不存在，抛出异常
		if(customer.getOperate()==OPERATE_TYPE_MODIFY){
			if(customerCertificate==null){
				throw new BusinessException(TransErrorMgt.ENTITY_NOT_EXIST.code,
						String.format(TransErrorMgt.ENTITY_NOT_EXIST.message,"客户证件信息"));
			}

			// 客户证件信息存在，输入客户编号与数据库中的客户编号不一致，抛出异常
			if(!customer.getCustomerNo().equals(customerCertificate.getCustomerNo())){
				throw new BusinessException(TransErrorMgt.CUSTOMER_NO_NOT_MATCH_CERTIFICATE.code,
						TransErrorMgt.CUSTOMER_NO_NOT_MATCH_CERTIFICATE.message);
			}

		}

		return false;
	}

//	@Transactional
	@Override
	public Boolean deleteCustomerCertificate(CustomerCertificateDTO certificateDTO){
		return certificateDataComponent.deleteCustomerCertificate(certificateDTO);
	}

//	@CompensatableTransactional(type= CompensatableTransactional.CompensationType.AT)
	@Override
	public CustomerCertificateDTO saveCustomerCertificate(CustomerCertificateDTO certificateDTO){

		checkCustInputValues(certificateDTO);

		if(certificateDTO.getOperate()==OPERATE_TYPE_CREATE){
			CustomerCertificate customerCertificate = new CustomerCertificate();
			BeanUtils.copyProperties(certificateDTO,customerCertificate);
			// 由请求上传客户编号
//			String custNo = generateCustNo(certificateDTO.getType());
//			certificateDTO.setCustomerNo(custNo);
//			customerCertificate.setCustomerNo(custNo);
			certificateDataComponent.saveCustomerCertificate(customerCertificate);
			logger.info("客户证件信息保存成功，证件类型：{}，证件编号：{}，姓名：{}，客户编号（新生成）：{}",
					certificateDTO.getIdType(),certificateDTO.getIdNo(),certificateDTO.getName(),certificateDTO.getCustomerNo());
		}

		return certificateDTO;
	}
	@Override
	public CustomerCertificateDTO getCustomerCertificate(CustomerCertificateDTO customerCertificate){

		CustomerCertificateDTO customerCertificateDTO = new CustomerCertificateDTO();
		CustomerCertificate certificate = certificateDataComponent.
				getCustomerCertificate(customerCertificate.getIdType(),customerCertificate.getIdNo(),customerCertificate.getName());
		if(certificate==null){
			throw new BusinessException(TransErrorMgt.ENTITY_NOT_EXIST.code,
					String.format(TransErrorMgt.ENTITY_NOT_EXIST.message,"客户证件信息"));
		}

		BeanUtils.copyProperties(customerCertificate,customerCertificateDTO);

		return customerCertificateDTO;
	}


	private void checkCustInputValues(String idType, String idNo, String name){
		CreateCustomerDTO customerDTO = new CreateCustomerDTO();
		customerDTO.setIdType(idType);
		customerDTO.setIdNo(idNo);
		customerDTO.setName(name);
		checkCustInputValues(customerDTO);
	}

	private void checkCustInputValues(CustomerCertificateDTO certificateDTO){

		if(OPERATE_TYPE_MODIFY==certificateDTO.getOperate()){
			if(StringUtil.isNullOrEmpty(certificateDTO.getCustomerNo())){
				throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
						String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户编号"));
			}
		}

		if(StringUtil.isNullOrEmpty(certificateDTO.getIdType())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"证件类型"));
		}

		if(StringUtil.isNullOrEmpty(certificateDTO.getIdNo())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"证件号码"));
		}

		if(StringUtil.isNullOrEmpty(certificateDTO.getName())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户姓名"));
		}
	}

	private void checkCustInputValues(CreateCustomerDTO customerDTO){

		if(customerDTO.getOperate()==OPERATE_TYPE_MODIFY){
			if(StringUtil.isNullOrEmpty(customerDTO.getCustomerNo())){
				throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
						String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户编号"));
			}
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getIdType())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"证件类型"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getIdNo())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"证件号码"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getName())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户姓名"));
		}
	}

	private void checkCustExtendInputValues(CreateCustomerDTO customerDTO){
		if(StringUtil.isNullOrEmpty(customerDTO.getBirthday())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"出生日期"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getGender())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"性别"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getNationality())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"国籍"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getResidenceCountry())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"居住国"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getRegistrarType())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"户籍"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getCategory())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户类别"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getCustGroup())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户群"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getCustLevel())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户等级"));
		}

		if(StringUtil.isNullOrEmpty(customerDTO.getMobileNumber())){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"手机号码"));
		}

	}

//	@Override
//	@CompensatableTransactional(type= CompensatableTransactional.CompensationType.AT)
	@Override
	public int addNewCustomer(CreateCustomerDTO customerDTO) {

		checkCustInputValues(customerDTO);

		checkCustExtendInputValues(customerDTO);

		CustomerInfo customerInfo = null;
		try{
			customerInfo = customerDataComponent.getCustByNo(customerDTO.getCustomerNo());
		}catch (BusinessException e){
			if(e.getCode().equals(TransErrorMgt.ENTITY_NOT_EXIST.code)){
				// nothing to do
				// customer information is not exist
			}else {
				throw (e);
			}
		}

		// 如果为新建客户，且客户已经存在，则抛出异常
		if(customerDTO.getOperate()==OPERATE_TYPE_CREATE){
			if(customerInfo!=null && !StringUtils.isEmpty(customerInfo.getCustomerNo())){
				throw new BusinessException(TransErrorMgt.CUSTOMER_CERTIFICATE_IS_EXIST.code,
						String.format(TransErrorMgt.CUSTOMER_CERTIFICATE_IS_EXIST.message,customerInfo.getCustomerNo()));
			}
		}

		customerInfo = new CustomerInfo();
		BeanUtils.copyProperties(customerDTO, customerInfo);
		customerInfo.setTransNo(UUID.randomUUID().toString());

		if(StringUtil.isNullOrEmpty(customerInfo.getTransNo())){
			// todo set customer number
			//customerInfo.setTransNo(snowFlakeIdGenerator.nextId());
		}

		int result = 0;
		if(customerDTO.getOperate()==OPERATE_TYPE_CREATE){
			customerInfo.setTransDate(new Date());
			result = customerDataComponent.saveCustomer(customerInfo);
			logger.info("客户信息保存成功，证件类型：{}，证件编号：{}，姓名：{}，客户编号：{}，交易流水号：{}",
					customerDTO.getIdType(),customerDTO.getIdNo(),customerDTO.getName(),customerDTO.getCustomerNo(),customerInfo.getTransNo());
		}else{
			customerInfo.setUpdateDt(new Date());
			result = customerDataComponent.updateCustomer(customerInfo);
			logger.info("客户信息更新成功，证件类型：{}，证件编号：{}，姓名：{}，客户编号：{}，交易流水号：{}",
					customerDTO.getIdType(),customerDTO.getIdNo(),customerDTO.getName(),customerDTO.getCustomerNo(),customerInfo.getTransNo());
		}

		return result;
	}







	/***
	 * 根据客户编号查询客户信息
	 * @param customerNo 客户编号
	 * @return 客户信息
	 */
	@Override
	public QueryCustomerRespDTO getCustomerByNo(String customerNo) {

		if(StringUtil.isNullOrEmpty(customerNo)){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户编号"));
		}

		CustomerInfo customerInfo = customerDataComponent.getCustByNo(customerNo);

		QueryCustomerRespDTO customerDetailDTO = new QueryCustomerRespDTO();

		BeanUtils.copyProperties(customerInfo, customerDetailDTO);

		return customerDetailDTO;
	}

	/***
	 * 根据客户证件类型、证件号码、姓名查询客户信息
	 * @param idType 客户证件类型
	 * @param idNo 客户证件号码
	 * @param name 客户姓名
	 * @return 客户信息
	 */
	@Override
	public QueryCustomerRespDTO getCustomer(String idType, String idNo, String name) {

		checkCustInputValues(idType,idNo,name);

		CustomerInfo customerInfo = customerDataComponent.selectByUnionKeys(idType,
				idNo, name);

		QueryCustomerRespDTO customerDetailDTO = new QueryCustomerRespDTO();

		BeanUtils.copyProperties(customerInfo, customerDetailDTO);

		return customerDetailDTO;

	}

	@Override
	public QueryCustomerRespDTO getCustomer(CustomerCertificateDTO certificateDTO) {
		return this.getCustomer(certificateDTO.getIdType(), certificateDTO.getIdNo(), certificateDTO.getName());
	}

	/***
	 * 获取同一客户同一产品下所有的账户信息
	 * @param custNo 客户编号
	 * @param productNo 产品编号
	 * @param accountCategory 客户类别
	 * @return 客户账户列表
	 */
	@Override
	public List<CustomerAccountRelDTO> getCustSingleProductAccts(String custNo, String productNo,String accountCategory){

		if(StringUtil.isNullOrEmpty(custNo)){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,
					String.format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"客户编号"));
		}

		if(StringUtil.isNullOrEmpty(productNo)){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,String.
					format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"产品编号"));
		}

		if(StringUtil.isNullOrEmpty(accountCategory)){
			throw new BusinessException(TransErrorMgt.PARAM_VALUE_IS_NULL.code,String.
					format(TransErrorMgt.PARAM_VALUE_IS_NULL.message,"账号种类"));
		}

		List<CustomerAccountRelDTO> custAcctRels = new ArrayList<>();

		// 获取客户下所有账户数据
		List<CustomerAccountRel> custAcctInfo = customerDataComponent.getCustSingleProductAccts(custNo, productNo, accountCategory);

		// 客户账户状态检查并统计有效账户的数据
		if(custAcctInfo!=null && !custAcctInfo.isEmpty()){
			custAcctInfo.forEach(item -> {
				CustomerAccountRelDTO dto = new CustomerAccountRelDTO();
				BeanUtils.copyProperties(item,dto);
				custAcctRels.add(dto);
			});
			logger.info("客户编号：{}，产品编号：{}，已开账户数：{}",custNo,productNo,custAcctInfo.size());
		}

		return custAcctRels;
	}

	@Override
	public List<CustomerAccountRelDTO> getCustSingleProductAccts(CustomerAccountRelDTO customerAccountRelDTO) {
		return this.getCustSingleProductAccts(customerAccountRelDTO.getCustomerNo(),
				customerAccountRelDTO.getProductNo(),customerAccountRelDTO.getAccountCategory());
	}

	@Override
	public Integer savingCustAcctRel(CustomerAccountRelDTO custAcctRelDto){

		CustomerAccountRel custAcctRel = new CustomerAccountRel();
		BeanUtils.copyProperties(custAcctRelDto,custAcctRel);

		Integer result = customerDataComponent.saveCustAcctRel(custAcctRel);
		logger.info("客户编号：{}，新开账号：{}，客户与账号关系保存成功。",custAcctRelDto.getCustomerNo(),custAcctRelDto.getAccountNo());
		return result;
	}

	public void initCust(CustomerInfo custDto) {
		customerDataComponent.initCust(custDto);
	}

	public void initCustAcctRel(CustomerAccountRel custAcctRel) {
		customerDataComponent.initCustAcctRel(custAcctRel);
	}

	@Override
	public Integer deleteCustomer(String idType, String idNo, String name) {
		return customerDataComponent.deleteCustomer(idType, idNo, name);
	}


//	public List<QueryCustomerRespDTO> getCustomerByDate(String transDate) {
//
//		return customerDataComponent.getCustomerByDate(transDate);
//	}

	@Override
	public List<CustAcctRelDTO> selectAcctsByCustNo(String custNo) {
		List<CustomerAccountRel> records=customerDataComponent.selectAcctsByCustNoPagination(custNo);
		List<CustAcctRelDTO> result= new ArrayList<>();
		for (CustomerAccountRel record:records){
			CustAcctRelDTO dto=new CustAcctRelDTO();
			dto.setAccountNo(record.getAccountNo());
			dto.setAccountCategory(record.getAccountCategory());
			result.add(dto);
		}
		return result;
	}

	@Override
	public void deleteCustAcctRel(CustomerAccountRelDTO custAcctRel) {
		customerDataComponent.deleteCustAcctRel(custAcctRel);
	}

//	@Override
//	public int saveOperationLog(CustomerOperationLogDTO operationLogDTO) {
//
//		return customerOperationLogBasisCpnt.insertSelective(operationLogDTO);
//
//	}

	//    CustomerOperationLogBasisCpnt customerOperationLogBasisCpnt;



//	@Autowired
//	public void setCustomerOperationLogBasisCpnt(CustomerOperationLogBasisCpnt customerOperationLogBasisCpnt) {
//		this.customerOperationLogBasisCpnt = customerOperationLogBasisCpnt;
//	}

//    @Override
//    public List<CustomerOperationLogDTO> getOperationLogs(String customerNo, String startDate, String endDate) {
//        CustomerOperationLogDTO conditionDto = new CustomerOperationLogDTO();
//        PaginationCriteria extensionCriteria = PaginationCriteria.transPagination();
//
//        conditionDto.setCustomerNo(customerNo);
//        conditionDto.setStartDate(startDate);
//        conditionDto.setEndDate(endDate);
//
//        List<CustomerOperationLogDTO>  operationLogDTOS =  this.customerOperationLogBasisCpnt.
//                selectByDtoWithPagination(conditionDto,extensionCriteria);
//
//        return operationLogDTOS==null ? new ArrayList<>() : operationLogDTOS;
//    }

	@Override
	public List<CustAcctRelDTO> getAcctsByCustNo(String custNo) {
//		List<CustomerAccountRel> records=customerDataComponent.selectAcctsByCustNoPagination(custNo);
//		List<CustAcctRelDTO> result= new ArrayList<>();
//		for (CustomerAccountRel record:records){
//			CustAcctRelDTO dto=new CustAcctRelDTO();
//			dto.setAccountNo(record.getAccountNo());
//			dto.setAccountCategory(record.getAccountCategory());
//			result.add(dto);
//		}
//		return result;
		return null;
	}


}
